﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#endregion

namespace TheSpirit
{
    public abstract class Enemy
    {
        #region Declaration

        protected Attribute attribute;
        protected Animation animation;

        protected bool isAlive = false;
        protected bool isGoal = false;
        protected bool isAttacked = false;

        protected int velocity;
        protected int life;

        protected string name;

        protected Point worldLocation;
        protected Point localLocation;
        protected Point tileLocation;

        protected List<Tile> parent = new List<Tile>();

        #endregion


        #region Properties

        public bool IsAlive
        {
            set { isAlive = value; }
            get { return isAlive; }
        }
        public bool IsGoal
        {
            get { return isGoal; }
        }
        public bool IsAttacked
        {
            set { isAttacked = value; }
            get { return isAttacked; }
        }
        public int Velocity
        {
            get { return velocity; }
        }
        public int Life
        {
            get { return life; }
        }
        public string Name
        {
            get { return name; }
        }
        public Point WorldLocation
        {
            set { worldLocation = value; }
            get { return worldLocation; }
        }
        public Point LocalLocation
        {
            set { localLocation = value; }
            get { return localLocation; }
        }
        public Point TileLocation
        {
            set { tileLocation = value; }
            get { return tileLocation; }
        }
        public Animation Animations
        {
            get { return animation; }
        }

        #endregion


        #region Abstract Method 

        

        #endregion


        #region Method

        public void LoadContent(ContentManager content)
        {
            animation.AddAnimation(name + "Front", new AnimationStrip(content.Load<Texture2D>("Enemy/" + name + "Front"), 75, name + "Front"));
            animation.animations[name + "Front"].Setting(true, 0.3f);
            animation.AddAnimation(name + "Back", new AnimationStrip(content.Load<Texture2D>("Enemy/" + name + "Back"), 75, name + "Back"));
            animation.animations[name + "Back"].Setting(true, 0.3f);
            animation.AddAnimation(name + "Side", new AnimationStrip(content.Load<Texture2D>("Enemy/" + name + "Side"), 75, name + "Side"));
            animation.animations[name + "Side"].Setting(true, 0.3f);

            animation.PlayAnimation(name + "Front");
        }

        public void Update(GameTime gameTime, int x, int y, Tile[,] tile)
        {
            SetLocation(x, y);

            if (life <= 0)
            {
                tile[tileLocation.X, tileLocation.Y].tileState = Tile.TileState.Road;
                isAlive = false;
                return;
            }

            //적이 목표지점에 도착
            if (parent.Count == 0)
            {
                tile[tileLocation.X, tileLocation.Y].tileState = Tile.TileState.Road;
                isGoal = true;
                isAlive = false;
                return;
            }

            //적의 이동
            if (tileLocation.X - parent[0].TileLocation.X > 0)
            {
                animation.PlayAnimation(name + "Back");
                worldLocation.Y -= velocity;
            }
            else if (tileLocation.X - parent[0].TileLocation.X < 0)
            {
                animation.PlayAnimation(name + "Front");
                worldLocation.Y += velocity;
            }
            else if (tileLocation.Y - parent[0].TileLocation.Y > 0)
            {
                animation.PlayAnimation(name + "Side");
                animation.Flipped = true;
                worldLocation.X -= velocity;
            }
            else if (tileLocation.Y - parent[0].TileLocation.Y < 0)
            {
                animation.PlayAnimation(name + "Side");
                animation.Flipped = false;
                worldLocation.X += velocity;
            }

            int h = tile[parent[0].TileLocation.X, parent[0].TileLocation.Y].WorldLocation.X +
            (tile[parent[0].TileLocation.X, parent[0].TileLocation.Y].WorldLocation.Width -
            animation.animations[animation.CurrentAnimation].FrameWidth) / 2;

            int w = tile[parent[0].TileLocation.X, parent[0].TileLocation.Y].WorldLocation.Y +
            (tile[parent[0].TileLocation.X, parent[0].TileLocation.Y].WorldLocation.Height -
            animation.animations[animation.CurrentAnimation].FrameHeight) / 2;

            tile[tileLocation.X, tileLocation.Y].tileState = Tile.TileState.Road;
            tile[parent[0].TileLocation.X, parent[0].TileLocation.Y].tileState = Tile.TileState.Enemy;

            if (worldLocation.X == h && worldLocation.Y == w)
            {
                tileLocation.X = parent[0].TileLocation.X;
                tileLocation.Y = parent[0].TileLocation.Y;
                SetTile(tile);
                parent.RemoveAt(0);
            }

            animation.updateAnimation(gameTime);
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            int x = localLocation.X;
            int y = localLocation.Y;
            int w = animation.animations[animation.CurrentAnimation].FrameWidth;
            int h = animation.animations[animation.CurrentAnimation].FrameHeight;

            animation.DrawAnimation(spriteBatch, new Rectangle(x, y, w, h));
        }

        public void getDamage(int damage)
        {
            life -= damage;
        }

        public void SetTile(Tile[,] tile)
        {
            //타일의 상태 변경
            tile[tileLocation.X, tileLocation.Y].tileState = Tile.TileState.Enemy;

            //캐릭터의 전체화면상 위치 - 캐릭터의 바닥과 타일의 바닥을 맞춤
            worldLocation = new Point(tile[tileLocation.X, tileLocation.Y].WorldLocation.X +
                (tile[tileLocation.X, tileLocation.Y].WorldLocation.Width -
                animation.animations[animation.CurrentAnimation].FrameWidth) / 2,
                tile[tileLocation.X, tileLocation.Y].WorldLocation.Y +
                (tile[tileLocation.X, tileLocation.Y].WorldLocation.Height -
                animation.animations[animation.CurrentAnimation].FrameHeight) / 2);
        }
        
        public void SetLocation(int x, int y)
        {
            //캐릭터의 출력 화면상 위치
            localLocation.X = worldLocation.X - x;
            localLocation.Y = worldLocation.Y - y;
        }

        public void Explore(Tile[,] tile, int tileHeight, int tileWidth)
        {
            List<Tile> open = new List<Tile>();
            Dictionary<Tile, int> tileCount = new Dictionary<Tile, int>();

            int x = tileLocation.X;
            int y = tileLocation.Y;

            for (int i = 0; i < tileHeight; i++)
            {
                for (int j = 0; j < tileWidth; j++)
                {
                    if (tile[i, j].tileState == Tile.TileState.Road)
                    {
                        open.Add(tile[i, j]);
                    }
                }
            }
            parent.Add(tile[x, y]);
            open.Remove(tile[x, y]);

            while (open.Count != 0)
            {
                if (y - 1 >= 0)
                {
                    if (open.Contains(tile[x, y - 1]))
                    {
                        parent.Add(tile[x, y - 1]);
                        open.Remove(tile[x, y - 1]);
                        y = y - 1;
                        continue;
                    }
                }
                if (x - 1 >= 0)
                {
                    if (open.Contains(tile[x - 1, y]))
                    {
                        parent.Add(tile[x - 1, y]);
                        open.Remove(tile[x - 1, y]);
                        x = x - 1;
                        continue;
                    }
                }
                if (y + 1 <= tileWidth)
                {
                    if (open.Contains(tile[x, y + 1]))
                    {
                        parent.Add(tile[x, y + 1]);
                        open.Remove(tile[x, y + 1]);
                        y = y + 1;
                        continue;
                    }
                }
                if (x + 1 <= tileHeight)
                {
                    if (open.Contains(tile[x + 1, y]))
                    {
                        parent.Add(tile[x + 1, y]);
                        open.Remove(tile[x + 1, y]);
                        x = x + 1;
                        continue;
                    }
                }
            }
        }

        #endregion
    }
}
